using System.Collections.Generic;
using System.IO;
using System.Linq;
using EnvDTE;
using SolutionFactory.Services;

namespace SolutionFactory.Exporter
{
    public class FileCopyAndTokenReplacer
    {
        private readonly FileSystem _fileSystem;
        private readonly Logger _logger;
        private readonly FileTokenReplacer _fileTokenReplacer;

        public FileCopyAndTokenReplacer(FileSystem fileSystem,Logger logger,FileTokenReplacer fileTokenReplacer)
        {
            _fileSystem = fileSystem;
            _logger = logger;
            _fileTokenReplacer = fileTokenReplacer;            
        }

        public void InitializeTokenReplacer(string name)
        {
            var dictionary = new Dictionary<string, string>();
            dictionary.Add(name, "$safesolutionname$");
            _fileTokenReplacer.SetTokens(dictionary);
        }

        public void CopyProjectsToDestinationFolder(string destinationRootDirectory, Solution solution)
        {
            foreach (Project project in solution.Projects.GetCodeProjects())
            {
                string sourceFile = project.FileName;
                string destinationPath = Path.Combine(destinationRootDirectory.Combine(solution.GetDirectoryName()),
                                                      project.Name);
                string destinationFile = Path.Combine(destinationPath,
                                                      _fileSystem.GetFileNameWithExtension(project.FileName));
                _fileSystem.Copy(sourceFile, destinationFile);
                _fileTokenReplacer.Replace(destinationFile);
                if(project.ProjectItems!=null)
                {
                    CopyProjectItems(project.ProjectItems, destinationPath);
                }
            }
        }

        private void CopyProjectItems(ProjectItems items, string destinationPath)
        {
            foreach (ProjectItem projectItem in items)
            {
                if (projectItem.IsAFile())
                {
                    if (projectItem.IsLinkedFile())
                    {
                        string parentPath;
                        if (items.Parent is Project)
                        {
                            parentPath = Path.GetDirectoryName(((Project)items.Parent).FileName);
                        }
                        else
                        {
                            parentPath = Path.GetDirectoryName(((ProjectItem)items.Parent).get_FileNames(0));
                        }

                        string path = PathUtil.RelativePathTo(parentPath, projectItem.Folder());
                        string destinationFile = Path.Combine(destinationPath, path);
                        if (!_fileSystem.Exists(destinationFile))
                        {
                            _fileSystem.Copy(projectItem.Folder(), destinationFile);
                            _fileTokenReplacer.Replace(destinationFile);
                        }
                    }
                    else
                    {
                        for (short fileCount = 0; fileCount < projectItem.FileCount; fileCount++)
                        {
                            string file = projectItem.get_FileNames(fileCount);
                            string destinationFile = Path.Combine(destinationPath,
                                                                  _fileSystem.GetFileNameWithExtension(file));
                            //_logger.Log("Copying " + file);
                            _fileSystem.Copy(file, destinationFile);
                            _fileTokenReplacer.Replace(destinationFile);
                        }
                        if(projectItem.ProjectItems!=null)
                        {
                            CopyProjectItems(projectItem.ProjectItems, destinationPath);
                        }
                    }
                }
                else
                {
                    string folderPath = Path.Combine(destinationPath, projectItem.Name);
                    CopyProjectItems(projectItem.ProjectItems, folderPath);
                }
            }
        }




        public void CopyNonSolutionFiles(string destinationDirectory, Solution solution)
        {
            string solutionPath = _fileSystem.GetDirectoryName(solution.FileName);
            string trunkPath = _fileSystem.GetFullPath(Path.Combine(solutionPath, "..\\"));
            string solutionDirectoryName = solution.GetDirectoryName();
            CopyTrunkDirectories(trunkPath, string.Empty, destinationDirectory);
            CopyFilesAndTokenReplace(trunkPath, destinationDirectory);
            //CopySolutionFiles(solutionDirectoryName, destinationDirectory, solution);
        }

        private void CopyTrunkDirectories(string solutionDirRoot, string solutionParentDir, string dir)
        {
            foreach (string subDirectory in _fileSystem.GetSubDirectories(solutionDirRoot))
            {
                string subDirName = subDirectory.Replace(solutionDirRoot, "");
                if (subDirName != solutionParentDir && !subDirName.StartsWith("."))
                {
                    _logger.Log("Copying " + subDirectory);
                    string targetDir = Path.Combine(dir, subDirName);
                    string sourceDir = Path.Combine(solutionDirRoot, subDirName);
                    _fileSystem.CopyFilesAndDirectories(sourceDir, targetDir);
                }
            }
        }

        private void CopyFilesAndTokenReplace(string sourceDirectory, string destinationDirectory)
        {
            foreach (string file in _fileSystem.GetFilesInDirectory(sourceDirectory, "*.*"))
            {
                CopyFileAndReplaceTokens(destinationDirectory, file);
            }
        }

        private void CopySolutionFiles(string solutionParentDir, string dir, Solution solution)
        {
            List<string> files = _fileSystem.GetFilesInDirectory(
                _fileSystem.GetDirectoryName(solution.FileName), "*.*").Where(
                s => !s.EndsWith(".user") &&
                     //!s.EndsWith(".sln") &&
                     !s.EndsWith(".suo") &&
                     !s.EndsWith(".cache")).ToList();

            string destinationDir = dir.Combine(solutionParentDir);
            foreach (string file in files)
            {
                CopyFileAndReplaceTokens(destinationDir, file);
            }
        }

        private void CopyFileAndReplaceTokens(string destinationDir, string file)
        {
            string destinationFile = destinationDir.Combine(_fileSystem.GetFileNameWithExtension(file));
            _fileSystem.Copy(file, destinationFile);         

            if (FileShouldHaveTokensReplaced(destinationFile))
            {
                _logger.Log("Replacing tokens in " + destinationFile);
                _fileTokenReplacer.Replace(destinationFile);
            }
        }

        private bool FileShouldHaveTokensReplaced(string filename)
        {
            return _fileSystem.Exists(filename) &&  //some files may have been deleted post-copy
                   (
                        filename.EndsWith(".bat") ||
                        filename.EndsWith(".txt") ||
                        filename.EndsWith(".build") ||
                        filename.EndsWith(".config") ||
                        filename.EndsWith(".cs") ||
                        filename.EndsWith(".xml")
                   );
        }
    }
}